home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 015 / prtspool.arc / SPOOL.ASM < prev    next >
Encoding:
Assembly Source File  |  1985-03-08  |  34.5 KB  |  967 lines

  1.     PAGE    64,132
  2. ;----------------------------------------------------------------------------    
  3. ;    SPOOLER PROGRAM
  4. ;
  5. ;      Modified by Craig Derouen 6-6-84
  6. ;
  7. ;----------------------------------------------------------------------------
  8. CSEG    SEGMENT PARA PUBLIC 'CODE'
  9.     ASSUME    CS:CSEG,ES:CSEG,DS:CSEG
  10. ;----------------------------------------------------------------------------
  11. ;            DEVICE DRIVER HEADER
  12. ;----------------------------------------------------------------------------
  13. NEXT_DEV    DD    -1        ;POINTER TO NEXT DEVICE
  14. ATTRIBUTE    DW    8000H        ;CHARACTER TYPE DEVICE
  15. STRATEGY    DW    DEV_STRATEGY    ;POINTER TO DEVICE STRATEGY
  16. INTERRUPT    DW    DEV_INT        ;POINTER TO DEV_INT
  17. DEV_NAME    DB    'PRN     '    ;DEVICE INDENTIFIER
  18. ;-----------------------------------------------------------------------------
  19. ;         F U N C T I O N  T A B L E
  20. ;
  21. ;    This is the table of procedures which are called to service each type
  22. ; of device driver request from MS-DOS.
  23. ;-----------------------------------------------------------------------------
  24. FUNTAB        LABEL    BYTE
  25.         DW    INIT        ;INITIALIZATION ROUTINE
  26.         DW    EXIT        ;MEDIA CHECK (BLOCK ONLY)
  27.         DW    EXIT        ;BUILD BPB     ""     ""
  28.         DW    IOCTL_IN    ;IOCTL INPUT
  29.         DW    EXIT        ;INPUT (READ)
  30.         DW    ND_INPUT    ;NON_DESTRUCTIVE INPUT NO WAIT (CHAR ONLY)
  31.         DW    EXIT        ;INPUT STATUS
  32.         DW    EXIT        ;INPUT FLUSH
  33.         DW    OUTPUT        ;OUTPUT (WRITE)
  34.         DW    OUTPUT        ;OUTPUT (WRITE) WITH VERIFY
  35.         DW    OUT_STAT    ;OUTPUT STATUS
  36.         DW    OUT_FLUSH    ;OUTPUT FLUSH
  37.         DW    EXIT        ;IOCTL OUTPUT
  38. ;-----------------------------------------------------------------------------
  39. ;        WORKING VARIABLES FOR BUFFERRING OF OUTPUT
  40. ;-----------------------------------------------------------------------------
  41. PORT_TYPE    DB    0        ;FLAG SPECIFYING LPT OR COM PORT - COM=0, LPT=1
  42. RH_SEG        DD    0        ;REQUEST HEADER POINTER - SEGMENT AND OFFSET
  43. DATA_SEG    DW    0        ;DATA SEGMENT FOR PRINTER DATA
  44. ENDING_ADDRESS    DW    0        ; this is the value past back to dos from the initialization routine
  45. PULL_PTR    DW    0        ;POINTS TO THE CURRENT CHARACTER TO OUTPUT FROM THE BUFFER
  46. INSERT_PTR    DW    0        ;POINTS PLACE TO INSERT NEXT CHARACTER INTO BUFFER
  47. BUF_SIZE    DW    0        ;SIZE OF THE PRINTER BUFFER IN CHARACTERS
  48. PORT_NUMBER    DB    0        ;CURRENT PORT NUMBER OF OUTPUT PORT (0,1) if com, (0,1,2) if parallel
  49. MOVE_CNT    DW    0        ;AMOUNT OF DATA MOVED
  50. BUF_FLG        DB    0        ;NOT ZERO IF BUFFER FULL
  51. BUFF_CNT    DW    0        ;AMOUNT OF DATA IN THE BUFFER
  52. LOOP_CNT    DW    0        ;NUMBER OF TIMES AROUND THE LOOP
  53. PRIORITY    DW    100        ;PROCESSING PRIORITY
  54. POINTER_SET    DB    0        ;NON-ZERO IF IRQ0 VECTOR MODIFYIED
  55. ;-----------------------------------------------------------------------------
  56. ;                DEVICE STRATEGY ROUTINE
  57. ;
  58. ;    This procedure gets the request header from MS-DOS and sets up RH_SEG
  59. ; as the pointer used in the buffer driver for manipulation of the request
  60. ; header
  61. ;    ENTRY:    EX:BX --> pointer to request header from MS-DOS
  62. ;
  63. ;    EXIT:    RH_SEG --> our internal pointer to request header
  64. ;-----------------------------------------------------------------------------
  65. DEV_STRATEGY    PROC    FAR
  66.     MOV    WORD PTR CS:[RH_SEG],BX        ;SAVE THE REQUEST HEADER SEGMENT
  67.     MOV    WORD PTR CS:[RH_SEG+2],ES    ;SAVE THE REQUEST HEADER OFFSET
  68.     RET
  69. DEV_STRATEGY    ENDP
  70. ;------------------------------------------------------------------------------
  71. ;
  72. ;                DEVICE INTERRUPT HANDLER
  73. ;
  74. ;    This procedure is called each time MS-DOS calls the driver.  Its task
  75. ; is to branch control to the proper procedure to service the request.
  76. ;
  77. ;    This procedure saves all registers, uses RH_SEG (pointer to request 
  78. ; header) to get the command number, then uses the command number as an offset
  79. ; into the command table (FUNTAB) to jump to the appropriate procedure to service
  80. ; the request from MS-DOS to the driver
  81. ;
  82. ;    ENTRY:    RH_SEG --> pointer to request header
  83. ;
  84. ;    EXIT:    CX --> number of bytes to transfer (read or write)
  85. ;        EX:DI --> pointer to data (transfer address)
  86. ;        Jump to proper procedure to service request, if valid, or
  87. ;        jump to IOCTL_IN if invalid command
  88. ;-----------------------------------------------------------------------------
  89. DEV_INT    PROC    FAR
  90.     PUSH    SI
  91.     MOV    SI,OFFSET FUNTAB    ;POINT TO THE START OF THE FUNCTION TABLE
  92.     PUSH    AX            ;SAVE ALL REGISTERS ONTO THE STACK
  93.     PUSH    BX
  94.     PUSH    CX
  95.     PUSH    DX
  96.     PUSH    DI
  97.     PUSH    BP
  98.     PUSH    DS
  99.     PUSH    ES
  100.     LDS    BX,CS:RH_SEG        ;GET THE REQUEST HEADER SEGMENT
  101.     MOV    CX,[BX+12H]        ;GET THE AMOUNT OF DATA TO TRANSFER
  102.     MOV    AL,[BX+02H]        ;GET THE COMMAND BYTE
  103.     CBW                ;MAKE 16 BIT VALUE
  104.     ADD    SI,AX            ;ADD INTO OUR TABLE VALUE
  105.     ADD    SI,AX            ;DO IT AGAIN
  106.     CMP    AL,0BH            ;IS IT ABOVE THE LAST ENTRY IN OUR TABLE
  107.     JA    IOCTL_IN        ;DO NULL ACTION IF SO
  108.     LES    DI,[BX]+14D        ;GET POINTER TO OUR DATA
  109.     PUSH    CS            ;MAKE OUR DATA SEGMENT REGISTER
  110.     POP    DS            ;THE SAME AS OUR CODE SEGMENT REGISTER
  111.     JMP    WORD PTR[SI]        ;JUMP TO CORRECT ACTION IN THE TABLE
  112. ;-----------------------------------------------------------------------------
  113. ;            NON DESTRUCTIVE INPUT ROUTINE
  114. ;
  115. ;    This procedure always returns done and busy to MS-DOS to indicate that
  116. ; there is no character in the buffer to return.
  117. ;
  118. ;    ENTRY:    RH_SEG --> pointer to request header from MS-DOS
  119. ;
  120. ;    EXIT:    RH_SEG --> return request header with done and busy set in 
  121. ; status word, no other changes are made to the request header
  122. ;        AH --> 0011 (done and busy bits set)
  123. ;----------------------------------------------------------------------------
  124. ND_INPUT:
  125.     MOV    AH,03            ;INDICATE DONE AND BUZY TO DOS
  126.     JMP    SHORT EXIT1        ;SET OUR STATUS WORD
  127. ;-----------------------------------------------------------------------------
  128. ;            IO CONTROL INPUT ROUTINE
  129. ;
  130. ;    This procedure always returns unknown command, done, and error in the 
  131. ; status word of the request header
  132. ;
  133. ;    ENTRY:    RH_SEG: --> pointer to request header from MS-DOS
  134. ;
  135. ;    EXIT:     RH_SEG: --> return request header with unknown command, done,
  136. ; and error bits set in status word
  137. ;----------------------------------------------------------------------------
  138. IOCTL_IN:
  139.     MOV    AL,03            ;INDICATE UNKNOWN COMMAND
  140.     MOV    AH,81H            ;INDICATE DONE AND ERROR
  141.     JMP    SHORT EXIT1        ;SET OUR STATUS WORD
  142. ;-----------------------------------------------------------------------------
  143. ;                 DUMMY RETURN POINT
  144. ;
  145. ;    This is the return procedure for exiting the driver and returning control
  146. ; to MS-DOS.  The status word can be updated to indicate done and number of 
  147. ; characters processed.  The registers which were previously saved are restored
  148. ; prior to exiting.
  149. ;
  150. ;    ENTRY:     AX,CX --> AH and AL can be previously set as the status word 
  151. ; should be JMPed to.
  152. ;
  153. ;    EXIT:    DS:BX --> pointer to update request header to return to MS-DOS
  154. ;        ES,DS,BP,DI,DX,CX,BX,AX,SI restored in that order
  155. ;-----------------------------------------------------------------------------
  156. EXIT:    MOV    AH,01            ;INDICATE DONE FOR STATUS WORD
  157.     MOV    CX,CS:MOVE_CNT        ;GET THE AMOUNT OF DATA MOVE
  158. EXIT1:    LDS    BX,CS:RH_SEG        ;LOAD REQUEST HEADER SEGMENT
  159.     MOV    [BX+03],AX        ;SAVE OUR EXIT STATUS WORD
  160.     MOV    [BX+12H],CX        ;SAVE THE AMOUNT OF DATA READ 
  161.     POP    ES            ;RESTORE THE ENTRY REGISTERS FROM THE
  162.     POP    DS            ;STACK BEFORE EXITING
  163.     POP    BP
  164.     POP    DI
  165.     POP    DX
  166.     POP    CX
  167.     POP    BX
  168.     POP    AX
  169.     POP    SI
  170.     RET
  171. DEV_INT    ENDP
  172. ;-----------------------------------------------------------------------------
  173. ;                OUTPUT STATUS ROUTINE
  174. ;
  175. ;    This procedure returns status based on the amount of characters in the
  176. ; buffer.  If the buffer is full (BUFF_CNT = BUF_SIZE) then a JMP to ND_INPUT
  177. ; is done to return busy and done to MS-DOS, otherwise a JMP to EXIT is done
  178. ; to return done.
  179. ;
  180. ;    ENTRY:    BUFF_CNT, BUF_SIZE are compared to see if the buffer is full
  181. ;
  182. ;    EXIT:    a jump is performed based on the amount of characters in the
  183. ; buffer.
  184. ;-----------------------------------------------------------------------------
  185. OUT_STAT    PROC    NEAR
  186. OUT_STAT1:MOV    BX,BUFF_CNT        ;GET AMOUNT OF CHARACTERS IN THE BUFFER
  187.     CMP    BX,BUF_SIZE        ;IS IT THE SAME AS OUR TOTAL BUFFER SPACE
  188.     JNZ    EXIT            ;INDICATE DONE TO DOS
  189.     JMP    ND_INPUT        ;INDICATE BUZY AND DONE TO THE OPERATING SYSTEM
  190. OUT_STAT    ENDP
  191. ;------------------------------------------------------------------------------
  192. ;                OUTPUT ROUTINE
  193. ;
  194. ;    This procedure services all write requests from MS-DOS.  This is done by
  195. ; inserting characters into the buffer until all characters have been inserted.
  196. ; Each character is put into AL and then INSERT is called which performs the
  197. ; insertion into the buffer.  This is performed repeatedly until all characters
  198. ; have been transferred into the buffer.
  199. ;
  200. ;    ENTRY:    CX --> number of characters to transfer into the buffer
  201. ;        ES:DI --> pointer to data area of characters to transfer
  202. ;
  203. ;    EXIT:    MOVE_CNT --> number of characters transferred into the buffer
  204. ;-----------------------------------------------------------------------------
  205. OUTPUT    PROC    NEAR
  206.     STI                ;START INTERRUPTS JUST IN CASE
  207. OUTPUT1:CLD                ;CLEAR DIRECTION FLAG
  208.     MOV    MOVE_CNT,0        ;SET NUMBER OF CHARACTERS ACCEPTED TO ZERO
  209. OUTPUT2:MOV    AL,ES:[DI]        ;GET THE CHARACTER FROM REQUESTER
  210.     CALL    INSERT            ;INSERT THE CHARACTER INTO LOCAL BUFFER
  211.     INC    MOVE_CNT        ;INCREMENT THE AMOUNT OF DATA MOVED
  212.     INC    DI            ;BUMP THE POINTER TO THE NEXT CHARACTER
  213.     LOOP    OUTPUT2            ;LOOP UNTILL ALL DATA INSERTED INTO THE BUFFER
  214.     JMP    EXIT            ;SET STATUS WORD TO DONE AND EXIT
  215. OUTPUT    ENDP
  216. ;-----------------------------------------------------------------------------
  217. ;            INSERT CHARACTER INTO PRINTER BUFFER
  218. ;
  219. ;    This procedure performs the task of inserting characters into the buffer.
  220. ; The procedure does an idle loop while the buffer is full because the buffer is
  221. ; being emptied in a background method.  Once there is room in the buffer, the
  222. ; INSERT_PTR is incremented to point to the next position.  If it points past
  223. ; the end of the buffer, it is set to point to the front of the buffer (a 
  224. ; circular queue).  Once the correct insert point is established, the character
  225. ; is written to memory and the buffer count is incremented to indicate the
  226. ; insertion of the character.  Interrupts are disabled for the short period
  227. ; when the character is actually written to memory and the buffer count is 
  228. ; incremented.
  229. ;
  230. ;    ENTRY:    AL --> character to insert into the buffer
  231. ;        BUFF_CNT --> number of characters currently in buffer
  232. ;        BUFF_SIZE --> size of buffer, also is address of last character
  233. ;        in buffer
  234. ;        INSERT_PTR --> pointer to last character placed into buffer
  235. ;        DATA_SEG --> data segment of buffer data
  236. ;    
  237. ;    EXIT:    INSERT_PTR --> pointer to character just inserted into buffer
  238. ;        BUFF_CNT --> updated number of characters in buffer
  239. ;        
  240. ;-----------------------------------------------------------------------------
  241.  
  242. INSERT    PROC    NEAR
  243. ;-----------------------------------------------------------------------------
  244. ; The following code needs to be checked to see if it is necessary (probably
  245. ;-----------------------------------------------------------------------------
  246.          CMP    POINTER_SET,0        ;IT TIMER INTERRUPT MODIFYED YET
  247.         JNZ    INSERT1            ;CONTINUE IF SO
  248.         PUSH    ES            ;SAVE CURRENT EXTRA SEGMENT
  249.         MOV    BX,0            ;SET THE SEGMENT ADDRESS TO ZERO
  250.         MOV    ES,BX            ;DO IT
  251.         MOV    BX,20H            ;ADDRESS OF INT VECTOR 08
  252.         MOV    WORD PTR ES:[BX],OFFSET PRTOUT    ;SET THE PRINT OUT ADDRESS
  253.         MOV    ES:[BX+2],CS        ;SET THE SEGMENT
  254.         POP    ES            ;RESTORE OUR PREVIOS EXTRA SEGMENT
  255.         MOV    POINTER_SET,0FFH    ;SET THE POINTER FLAG
  256. INSERT1:
  257.     MOV    BX,BUFF_CNT        ;GET THE CURRENT BUFFER COUNT
  258.     CMP    BUF_SIZE,BX        ;CHECK FOR BUFFER FULL
  259.     JZ    INSERT            ;LOOP UNTILL SPACE IS AVAILABLE
  260.     PUSH    DS            ;SAVE DATA SEGMENT
  261.     PUSH    AX            ;SAVE THE CHARACTER ONTO THE STACK
  262.     INC    INSERT_PTR        ;BUMP INSERT POINTER ONE POSITION
  263.     MOV    BX,BUF_SIZE        ;GET THE LAST POSITION IN THE BUFFER
  264.     CMP    INSERT_PTR,BX        ;ARE THEY THE SAME
  265.     JBE    INSERT2            ;CONTINUE IF NOT
  266.     MOV    INSERT_PTR,0        ;RESET THE POINTER TO BEGGING OF BUFFER
  267. INSERT2:MOV    SI,INSERT_PTR        ;GET THE CURRENT INSERT POINTER
  268.     MOV    DS,DATA_SEG        ;GET THE DATA SEGMENT OF OUR BUFFER
  269.     POP    AX            ;RESTORE OUR CHARACTER FROM THE STACK
  270.     CLI                ;STOP INTERRUPTS
  271.     MOV    [SI],AL            ;PUT IT INTO MEMORY
  272.     POP    DS            ;RESTORE OUR LOCAL DATA SEGMENT REGISTER
  273.     INC    BUFF_CNT        ;INCREMENT COUNT OF CHARACTERS IN BUFFER
  274.     STI                ;RESTART INTERRUPTS
  275.     RET
  276. INSERT    ENDP
  277. ;-----------------------------------------------------------------------------
  278. ;            FLUSH BUFFER REQUEST ROUTINE
  279. ;
  280. ;    This procedure flushes the buffer by calling a procedure called FLUSH.
  281. ; It then JMPs to EXIT to set the status word to done and exits.
  282. ;-----------------------------------------------------------------------------
  283. OUT_FLUSH    PROC    NEAR
  284.     CALL    FLUSH            ;GO FLUSH CONTENTS OF THE MEMORY BUFFER
  285.     JMP    EXIT            ;SET STATUS WORD TO DONE AND EXIT
  286. OUT_FLUSH    ENDP
  287. ;-----------------------------------------------------------------------------
  288. ;            FLUSH BUFFER ROUTINE
  289. ;
  290. ;     This is the procedure which actually performs the clearing of the buffer.
  291. ; Interrupts are disabled during this action.  PULL_PTR, INSERT_PTR, BUFF_CNT
  292. ; are all zeroed.  This sets the amount of characters in the buffer to zero,
  293. ; front of the buffer.
  294. ;
  295. ;    ENTRY:    PULL_PTR --> pointer to next character to send to printer
  296. ;        INSERT_PTR --> pointer to last character inserted into buffer
  297. ;        BUFF_CNT --> number of characters currently in buffer
  298. ;
  299. ;    EXIT:    PULL_PTR, INSERT_PTR, BUFF_CNT --> all reset to zero (reset)
  300. ;-----------------------------------------------------------------------------
  301. FLUSH    PROC    NEAR
  302.     CLI                ;TURN OFF INTERRUPTS WHILE WE WORK
  303.     MOV    AX,0
  304.     MOV    PULL_PTR,AX        ;ZERO OUT THE PULL
  305.     MOV    INSERT_PTR,AX        ;AND INSERT POINTERS
  306.     MOV    BUFF_CNT,AX        ;RESET AMOUNT OF DATA AVAIL
  307.     STI                ;RESTART INTERRUPTS
  308.     RET
  309. FLUSH    ENDP
  310. ;-----------------------------------------------------------------------------
  311. ;            BUFFER STATUS ROUTINE ENTRY POINT
  312. ;
  313. ;    This is the interrupt procedure which is vectored to by interrupt 65H
  314. ; which was set up in INIT.  INT 65H is used by the BUFFER status program 
  315. ; to perform IO control functions of: Flushing the buffer, getting and setting
  316. ; the port number, getting the buffer size, amount of characters in the buffer,
  317. ; and getting and setting the processing priority (background or foreground).
  318. ; Since this status procedure is interrupt driven, it must save all registers,
  319. ; perform the desired operation, and return via an IRET (interrupt return).
  320. ; The AX register, on entry, contains the request number.  It is doubled and
  321. ; used as an offset into a table to determine the address of the servicing 
  322. ; procedure.  On exit from the servicing procedure, BX contains the requested 
  323. ; information.
  324. ;
  325. ;    ENTRY:    AX --> status request command number
  326. ;        
  327. ;    EXIT:    BX --> return value from status request servicing procedure
  328. ;            (buffer count, port number, etc.)
  329. ;-----------------------------------------------------------------------------
  330. STATUS    PROC    FAR
  331.     STI                ;RESTART INTERRUPTS
  332.     PUSHF                ;SAVE REGISTERS ONTO STACK
  333.     PUSH    CX
  334.     PUSH    SI
  335.     PUSH    DS
  336.     PUSH    CS
  337.     POP    DS
  338.     CMP    AX,7            ;TEST THE REQUEST
  339.     JB    STATUS1            ;CONTINUE IF VALID
  340.     MOV    AX,1            ;CHANGE IT TO A NUMBER ONE REQUEST
  341. STATUS1:ADD    AX,AX
  342.     MOV    SI,OFFSET TABLE        ;POINT TO START OF TABLE
  343.     XCHG    BX,AX            ;PUT IN BX 
  344.     MOV    SI,[BX+SI]        ;GET ROUTINE ADDRESS OUT OF TABLE
  345.     XCHG    BX,AX            ;SWAP BACK AROUND
  346.     CALL    SI            ;CALL THE REQUESTED ROUTINE
  347.     POP    DS            ;RESTORE OUR STACK
  348.     POP    SI            ;AND RETURN TO CALLING PROGRAM
  349.     POP    CX
  350.     POPF
  351.     IRET
  352. STATUS    ENDP
  353. ;-----------------------------------------------------------------------------
  354. ;            SPECIAL ACTION TABLE
  355. ;
  356. ;    This is the table of procedures to service the status requests from 
  357. ; INT 65H.  
  358. ;-----------------------------------------------------------------------------
  359. TABLE    DW    FLUSH            ;FLUSH BUFFER
  360.     DW    GET_PORT        ;GO GET THE PRINTER PORT NUMBER
  361.     DW    SET_PORT        ;REASSIGN PRINTER PORT
  362.     DW    GET_BUF_SIZ        ;GO GET PRINTER BUFFER SIZE
  363.     DW    GET_COUNT        ;GO GET COUNT OF CHARACTERS IN BUFFER
  364.     DW    SET_PRIORITY        ;SET CURRENT PROCESSING PRIORITY
  365.     DW    GET_PRIORITY        ;GET CURRENT PROCESSING PRIORITY
  366. ;-----------------------------------------------------------------------------
  367. ;            GET CURRENT PORT NUMBER
  368. ;
  369. ;     This procedure returns the current port number in the BL register as an
  370. ; ASCII digit 1-4 (31H-34H).
  371. ;
  372. ;    ENTRY:    PORT_NUMBER --> current port number the buffer is assigned to
  373. ;
  374. ;    EXIT:    BL --> ASCII digit of the current buffer port number
  375. ;        BH := port type. 0 com, 1 parallel
  376. ;-----------------------------------------------------------------------------
  377. GET_PORT PROC    NEAR
  378.     XOR    BX,BX            ;CLEAR OUT BX
  379.     MOV    BL,PORT_NUMBER        ;GET THE PRINTER PORT IN USE
  380.     MOV    BH,[PORT_TYPE]
  381.     RET
  382. GET_PORT    ENDP
  383. ;-----------------------------------------------------------------------------
  384. ;            GET CURRENT BUFFER SIZE
  385. ;
  386. ;    This procedure returns the current buffer size (capacity) in the BX
  387. ; register.  It is in the range of 0 to 65535.
  388. ;
  389. ;    ENTRY:    BUF_SIZE --> assigned capacity of the buffer 
  390. ;
  391. ;    EXIT:    BX --> assigned capacity of the buffer (0 - 65535)
  392. ;-----------------------------------------------------------------------------
  393. GET_BUF_SIZ    PROC    NEAR
  394.     MOV    BX,BUF_SIZE        ;LOAD VALUE OF OUR BUFFER SIZE
  395.     RET
  396. GET_BUF_SIZ    ENDP
  397. ;-----------------------------------------------------------------------------
  398. ;             REASSIGN PORT ROUTINE
  399. ;
  400. ;    This procedure sets the bufferred port number to the value received in
  401. ; the BL register from the INT 65H.
  402. ;
  403. ;    ENTRY:    BL --> new port number for bufferring (0,1) if com (0,1,2) if parallel
  404. ;        BH = port type. 0 com, 1 for parallel
  405. ;
  406. ;    EXIT:    PORT_NUMBER --> updated to new port number
  407. ;-----------------------------------------------------------------------------
  408. SET_PORT    PROC    NEAR
  409.     MOV    PORT_NUMBER,BL        ;SAVE THE NEW PORT NUMBER
  410.     MOV     [PORT_TYPE],BH
  411.     RET
  412. SET_PORT    ENDP
  413. ;-----------------------------------------------------------------------------
  414. ;         GET COUNT OF CHARACTERS IN PRINTER BUFFER
  415. ;
  416. ;    This procedure returns the amount of characters currently in the buffer
  417. ; waiting for output to the designated port.
  418. ;
  419. ;    ENTRY:    BUFF_CNT --> current amount of characters in buffer
  420. ;
  421. ;    EXIT:    BX -->    current amount of characters in buffer returned
  422. ;-----------------------------------------------------------------------------
  423. GET_COUNT    PROC    NEAR
  424.     MOV    BX,BUFF_CNT        ;GET AMOUNT OF DATA IN MEMORY BUFFER
  425.     RET
  426. GET_COUNT    ENDP
  427. ;-----------------------------------------------------------------------------
  428. ;            SET PROCESSING PRIORITY
  429. ;
  430. ;    This procedure sets the processing priority.  The priority dictates 
  431. ; how the character-output-to-the-port procedure services the output.  The
  432. ; priority is the maximum number of times the output procedure will loop 
  433. ; waiting for the port to become ready (not busy).  A low priority will only
  434. ;
  435. ;    ENTRY:    BX --> new priority number
  436. ;
  437. ;    EXIT:    PRIORITY --> updated priority number for use by the buffer
  438. ;-----------------------------------------------------------------------------
  439. SET_PRIORITY    PROC    NEAR
  440.     MOV    PRIORITY,BX        ;SAVE THE NEW PRIORITY
  441.     RET
  442. SET_PRIORITY    ENDP
  443. ;-----------------------------------------------------------------------------
  444. ;            GET PROCESSING PRIORITY
  445. ;
  446. ;    This procedure returns the current processing priority in the BX
  447. ; register.
  448. ;
  449. ;    ENTRY:    PRIORITY --> current processing priority
  450. ;
  451. ;    EXIT:    BX --> returned processing priority
  452. ;-----------------------------------------------------------------------------
  453. GET_PRIORITY    PROC    NEAR
  454.     MOV    BX,PRIORITY        ;GET THE CURRENT PROCESSING PRIORITY
  455.     RET
  456. GET_PRIORITY    ENDP
  457. ;-----------------------------------------------------------------------------
  458. ;        PARALLEL INTERRUPT INTERCEPT ROUTINE
  459. ;
  460. ;    This procedure is set-up as the new parallel printer interrupt routine.
  461. ; When an interrupt occurs, control is diverted to this routine.  A check is 
  462. ; performed to see if the port being output to is the port we have set-up a
  463. ; buffer for.  If it is not, then the regular, old IBM BIOS routine is called.
  464. ; We re-vectored the old IBM BIOS routine to INT 67h (pretty slick, huh?).
  465. ; Then a test is done to see if the desired action is to output a character, 
  466. ; initialize the port, or get the status of the port.  
  467. ; procedure.
  468. ; If the request is for a port status, our procedure checks to see if the 
  469. ; buffer is full, if it is full, we return BUSY and SELECTED in the AH status
  470. ; register.  If the buffer is not full, we return NOT BUSY and selected.
  471. ; If the request is to print a character in AL, all registers are saved,
  472. ; the INSERT procedure is called to insert the character in the buffer, and
  473. ; a status check is performed for return from the interrupt.
  474. ;
  475. ;    ENTRY:    AH --> interrupt request type (0,1,2)
  476. ;        AL --> character to output
  477. ;        DX --> port number to work with (status, output, etc)
  478. ;        PORT_NUMBER --> the currently bufferred output port
  479. ;        BUFF_CNT --> current number of characters in the buffer
  480. ;        BUF_SIZE --> current capacity of the buffer
  481. ;
  482. ;    EXIT:    AH --> port status returned
  483. ;-----------------------------------------------------------------------------
  484. PAR_INCEP    PROC    NEAR
  485.     STI                ;RESTART INTERRUPTS
  486.     CMP    CS:[PORT_TYPE],1    ; parallel=1, com=0
  487.     JNZ     PAR_INCEP9
  488.     CMP    DL,CS:PORT_NUMBER    ;IS IT THE PORT WE ARE DOING SPOOLING FOR
  489.     JNZ    PAR_INCEP9        ;TRANSFER CONTROL TO ROM BIOS IF NOT
  490.     CMP    AH,1            ;IS IT A RESET REQUEST
  491.     JZ    PAR_INCEP1        ;WAIT FOR BUFFER EMPTY AND RESET
  492.     CMP    AH,2            ;IS IT A STATUS REQUEST
  493.     JZ    PAR_INCEP2        ;MAKE STATUS DETERMINATION
  494.     CALL    INSERT_A_CHAR
  495. PAR_INCEP2:
  496.     PUSH    AX            ;SAVE INITAL REGISTER ONTO THE STACK
  497.     MOV    AX,CS:BUFF_CNT        ;GET CURRENT BUFFER COUNT
  498.     CMP    AX,CS:BUF_SIZE        ;IS BUFFER FULL ?
  499.     POP    AX            ;RESTORE AL FROM STACK
  500.     JZ    PAR_INCEP3        ;INDICATE BUZY                *** what about the rest of the status like out of paper
  501.     MOV    AH,90H            ;INDICATE NOT BUZY AND SELECTED
  502.     IRET
  503. PAR_INCEP3:
  504.     MOV    AH,10H            ;INDICATE SELECTED AND BUZY
  505.     IRET
  506. PAR_INCEP1:
  507.     CMP    CS:BUFF_CNT,0        ;IS BUFFER EMPTY
  508.     JNZ    PAR_INCEP1        ;LOOP UNTILL IT IS
  509. PAR_INCEP9:
  510.     INT    67h            ;HAND CONTROL OVER TO THE ROM BIOS
  511.     IRET                ;RETURN TO CALLING ROUTINE
  512. PAR_INCEP    ENDP
  513.  
  514. ;--------------------------------------------------------------------
  515.  
  516. COM_INCEP    PROC
  517. ; This routine will replace the IBM int 14h for RS232 communication.
  518.     STI
  519.     
  520.     CMP CS:[PORT_TYPE], 0        ; skip this routine if flash prn is using parallel
  521.     JNZ COM_INCEP9
  522.     
  523.     CMP CS:[PORT_NUMBER], DL    ; skip this routine if flash prn is using different com ports
  524.     JNZ COM_INCEP9    
  525.     
  526.     CMP AH, 0            ; skip if they want to set baud rate, etc
  527.     JZ COM_INCEP9
  528.     
  529.     CMP AH, 1            ; insert a char in the buffer
  530.     JZ COM_INCEP1
  531.     
  532.     CMP AH, 2            ; get a char (set error bits and return)
  533.     JZ COM_INCEP2
  534.     
  535.     CMP AH, 3            ; status
  536.     JZ COM_INCEP9
  537.     
  538.     IRET
  539.     
  540. COM_INCEP1:
  541.     CALL INSERT_A_CHAR
  542.     PUSH DX
  543.     CALL GET_PORT_ADDRESS
  544.     CALL GET_COM_STATUS
  545.     POP DX
  546.  
  547.     PUSH AX
  548.     MOV AX,CS:BUFF_CNT    ;if the buffer is full set the high bit of ah
  549.     CMP AX,CS:BUF_SIZE
  550.     POP AX
  551.     JNZ C1
  552.     OR AH, 80H
  553. C1:
  554.     IRET
  555.  
  556. COM_INCEP9:
  557.     INT 66H
  558.     IRET
  559. COM_INCEP2:            ; set all the error bits
  560.     MOV AH, 1001111B
  561.     IRET
  562. COM_INCEP    ENDP
  563.         
  564. ;--------------------------------------------------------------------
  565.  
  566. INSERT_A_CHAR    PROC
  567.  
  568.     PUSH    AX
  569.     PUSH    BX
  570.     PUSH    SI
  571.     PUSH    DS
  572. ;-----------------------------------------------------------------------------
  573. ;            ESTABLISH LOCAL ADDRESSING
  574. ;    This is an important section because it sets-up the correct data 
  575. ; segment for the buffer prior to calling INSERT to place the character in AL
  576. ; into the buffer.
  577. ;-----------------------------------------------------------------------------
  578.     PUSH    CS
  579.     POP    DS
  580.     CALL    INSERT            ;INSERT THE CHARACTER INTO THE PRINTER BUFFER
  581.     POP    DS
  582.     POP    SI            ;RESTORE SAVED REGISTERS
  583.     POP    BX            ;FROM THE STACK
  584.     POP    AX
  585.     RET
  586. INSERT_A_CHAR    ENDP
  587.  
  588. ;-----------------------------------------------------------------------------
  589. ;            DUMMY FARJUMP PROCEDURE
  590. ;     This procedure is initially a do-nothing procedure.  But, after INIT
  591. ; gets done with it, it is replaced by the IBM ROM BIOS timer interrupt routine.
  592. ; (Check out the JMP FARJMP instruction at the label PRTOUT9:).  The FARJMP
  593. ; label is replaced by INIT with the address of the timer interrupt routine.
  594. ; That way we can output a character from the buffer to the printer port and 
  595. ; then service the timer interrupt in the normal fashion using the same IBM
  596. ; BIOS routine (another slick move!!!).
  597. ;-----------------------------------------------------------------------------
  598. ;    FARJMP    PROC    FAR
  599. ;        RET
  600. ;        FARJMP    ENDP
  601. ;-----------------------------------------------------------------------------
  602. ;            PRINTER OUTPUT ROUTINE
  603. ;
  604. ;    This is the procedure that replaces the standard timer interrupt.  That
  605. ; way whenever the timer is interrupted we can try to get a character out of
  606. ; the buffer to the output port.  A neato trick is that the standard timer
  607. ; interrupt code is JMPed to at the very end of this code.  This way the 
  608. ; standard code is executed after ours (no applause, please!).  
  609. ; An important item to take note of is the fact that the data segment is 
  610. ; restored from the code segment prior to calling CHROUT.  The code segment
  611. ; stays the same throughout the driver.
  612. ;-----------------------------------------------------------------------------
  613. PRTOUT    PROC    NEAR
  614.     STI                ;RESTART INTERRUPTS FOR OTHER ACTIVITYS
  615.     PUSH    AX            ;SAVE THE REGISTERS WE WILL USE
  616.     PUSH    BX
  617.     PUSH    DX
  618.     PUSH    SI
  619.     PUSH    DS
  620.     PUSH    ES
  621.     PUSH    CS
  622.     POP    DS
  623.     CALL    CHROUT            ;DO CHARACTER OUT PROCESSING
  624.     POP    ES
  625.     POP    DS
  626.     POP    SI
  627.     POP    DX
  628.     POP    BX
  629.     POP    AX
  630. PRTOUT9:DB 0EAH,0,0,0,0            ;FAR JUMP TO OLD TIMER INTERRUPT ROUTINE
  631. PRTOUT    ENDP
  632. ;-----------------------------------------------------------------------------
  633. ;            PRINTER PORT CHARACTER OUTPUT ROUTINE
  634. ;
  635. ;    This procedure handles removing a character from the buffer and 
  636. ; outputting it to the designated port.  Alot of activities happens in this
  637. ; routine: buffer manipulation, status checking on the desired port and finally
  638. ; outputting the character to the data port.  
  639. ; The time-out counter (LOOP_CNT) is initialized to the processing priority.
  640. ; Really it is a counter that controls how many times to loop until the 
  641.     
  642. CHROUT    PROC    NEAR
  643.     MOV    AX,PRIORITY        ;GET CURRENT PRIORITY COUNT
  644.     MOV    LOOP_CNT,AX        ;SET NUMBER OF TIMES TO LOOP
  645. CHROUT1:
  646.     CMP    BUFF_CNT,0        ;IS THE BUFFER EMPTY
  647.     JZ    CHROUT9            ;EXIT IF SO
  648.     CALL    GET_PORT_ADDRESS
  649.     CALL    BUSYTEST
  650.     JC    CHROUT7
  651.     INC    PULL_PTR        ;BUMP THE PULL POINTER ONE CHR
  652.     MOV    BX,BUF_SIZE        ;GET MAX BUFFER SIZE
  653.     CMP    PULL_PTR,BX        ;TEST FOR OVERFLOW
  654.     JBE    CHROUT2            ;CONTINUE IF NO PROBLEM
  655.     MOV    PULL_PTR,0H        ;RESET POINTER TO BEGINING OF BUFFER
  656. CHROUT2:
  657.     MOV    SI,PULL_PTR        ;GET CURRENT PULL POINTER
  658.     MOV    ES,DATA_SEG        ;GET SEGMENT VALUE OF THE DATA BUFFER
  659.     CLI                ;TURN OFF INTERRUPTS
  660.     MOV    AL,ES:[SI]        ;GET CHARACTER OUT OF THE BUFFER
  661.     MOV     AH, AL
  662.     DEC    BUFF_CNT        ;ADDJUST BUFFER COUNT
  663.     CALL    OUTPUTAL
  664.     STI
  665.     CMP    AH,1BH            ;WAS IT SOME KIND OF CONTROL CHARACTER
  666.     JB    CHROUT9            ;EXIT AS THERE SHOULD BE A DELAY COMMING
  667. CHROUT8:DEC    LOOP_CNT        ;ADDJUST THE LOOP COUNT
  668.     JNZ    CHROUT1            ;LOOP IF NOT DONE
  669. CHROUT9:RET
  670. CHROUT7:MOV    AX,PRIORITY        ;GET CURRENT PRIORITY
  671.     CMP    LOOP_CNT,AX        ;HAS IT EVER BEEN READY
  672.     JNZ    CHROUT8            ;CONTINUE IF SO
  673.     RET
  674. CHROUT    ENDP
  675.  
  676. ;--------------------------------------------------------------------
  677.  
  678. GET_PORT_ADDRESS    PROC
  679. ; call: [port_type] = 0 com, 1 if parallel
  680. ;    [port_number] = 0, 1, 2
  681. ; return: dx = port address
  682.     PUSH AX
  683.     PUSH ES
  684.     PUSH SI
  685.  
  686.     MOV    AX,0040H        ;SET EXTRA SEGMENT TO LOOK
  687.     MOV    ES,AX            ;INTO THE ROMBIOS DATA AREA
  688.     MOV    SI,8            ;LOAD OFFSET TO PAR. PRINTER TABLE
  689.     CMP    CS:[PORT_TYPE], 0
  690.     JNZ    G1
  691.     MOV     SI, 0
  692. G1:
  693.     MOV    AL,CS:[PORT_NUMBER]    ;GET THE CURRENT PORT NUMBER
  694.     CBW                ;MAKE IT A 16 BIT VALUE
  695.     ADD    SI,AX            ;DO POWER OF TWO
  696.     ADD    SI,AX            ;TO COMPUTE DISPLACEMENT INTO ADDRESS TABLE
  697.     MOV    DX,ES:[SI]        ;GET PAR. PORT ADDRESS OUT OF THE TABLE
  698.     
  699.     POP SI
  700.     POP ES
  701.     POP AX
  702.     RET
  703. GET_PORT_ADDRESS    ENDP
  704.  
  705. ;--------------------------------------------------------------------
  706.  
  707. BUSYTEST    PROC
  708. ; call: dx = port address
  709. ;    [port_type] = 0 com, 1 par
  710. ; return: carry is set if a char. con not be output (busy).
  711.  
  712.     PUSH DX
  713.     CMP [PORT_TYPE], 1
  714.     JNZ COM_TEST
  715.     
  716.     INC    DX        ; parallel busy test
  717.     IN    AL,DX        
  718.     TEST    AL,80H        
  719.     JZ    BUSY_EXIT    
  720.     JMP NOT_BUSY_EXIT
  721. COM_TEST:
  722.     ADD DX, 6        ; com busy test
  723.     IN AL, DX
  724.     TEST AL, 20H
  725.     JZ BUSY_EXIT
  726.     TEST AL, 10H
  727.     JZ BUSY_EXIT
  728.     DEC DX
  729.     IN AL, DX
  730.     TEST AL, 20H
  731.     JZ BUSY_EXIT
  732.     JMP NOT_BUSY_EXIT
  733. BUSY_EXIT:
  734.     POP DX
  735.     STC
  736.     RET
  737. NOT_BUSY_EXIT:
  738.     POP DX
  739.     CLC
  740.     RET
  741. BUSYTEST    ENDP
  742.  
  743. ;--------------------------------------------------------------------
  744.  
  745. OUTPUTAL    PROC
  746. ; Output a character to the com or par. ports. Assume the port is not busy.
  747. ; call:    dx = port address
  748. ;    [port_type] = 0 com, 1 par
  749. ;    al = character to output
  750.     
  751.     CMP [PORT_TYPE], 1
  752.     JNZ COM_OUTPUT
  753.     
  754.     OUT DX, AL        ; parallel output (see IBM rom bios)
  755.     INC DX
  756.     MOV AL, 0DH
  757.     INC DX
  758.     OUT DX, AL
  759.     MOV AL, 0CH
  760.     OUT DX, AL
  761.     RET
  762. COM_OUTPUT:
  763.     PUSH AX            ; com output (see IBM rom bios)
  764.     ADD DX, 4
  765.     MOV AL, 3
  766.     OUT DX, AL
  767.     SUB DX, 4
  768.     POP AX
  769.     OUT DX, AL
  770.     RET
  771. OUTPUTAL    ENDP
  772.     
  773. ;--------------------------------------------------------------------
  774.  
  775. GET_COM_STATUS    PROC
  776. ; see IBM rom bios page a-23
  777. ; call:    dx = port address of com
  778. ; return: ah = line status
  779. ;      al = modem status
  780.  
  781.     ADD DX, 5        ; point to the control port
  782.     IN AL, DX        ; line control status
  783.     MOV AH, AL
  784.     INC DX
  785.     IN AL, DX        ; modem status
  786.     RET
  787. GET_COM_STATUS    ENDP
  788.  
  789. ;--------------------------------------------------------------------
  790.  
  791.     DB 16 DUP(?)
  792. ;
  793. ;    INIT ROUTINE
  794. ;
  795. INIT    PROC    NEAR
  796.     CLD                ;CLEAR DIRECTION
  797.     LDS    SI,RH_SEG        ;GET POINTER TO REQUEST HEADER
  798.     LDS    SI,18[SI]        ;GET POINTER TO CONFIG MESSAGE
  799. INIT1:    MOV    BX,1            ;START WITH A VALUE OF ONE K
  800.     LODSB                ;GET CHARACTER
  801.     CMP    AL,0DH            ;IS IT A RETURN
  802.     JZ    INIT3            ;EXIT DETERMINATION IF SO
  803.     CMP    AL,2FH            ;IS IT A SLASH SEPERATING VALUES 
  804.     JZ    INIT2            ;IF SO GET VALUE
  805.     CMP    AL,2DH            ;IS IT A DASH CHARACTER
  806.     JNZ    INIT1            ;LOOP IF NO DETERMINATION
  807. INIT2:    LODSB                ;GET HIGH ORDER CHARACTER
  808.     SUB    AL,30H            ;CONVERT TO BINARY
  809.     JB    INIT3            ;EXIT DETERMINATION IF NOT A DIGIT
  810.     CMP    AL,0AH            ;IS IF GREATER THEN THE NUMBER 9
  811.     JNB    INIT3            ;EXIT IF SO
  812.     MOV    BL,AL            ;PUT VALUE IN BL
  813.     CMP    BYTE PTR[SI],30H    ;CHECK NEXT CHARACTER TO SEE IF AN DIGIT
  814.     JB    INIT3            ;NOT A DIGIT GO ONTO NEXT TEST
  815.     LODSB                ;GET THE DIGIT
  816.     SUB    AL,30H            ;CONVERT TO BINARY
  817.     JB    INIT3
  818.     CMP    AL,0AH            ;CHECK FOR GREATER THEN 9
  819.     JNB    INIT3            ;GO ONTO NEXT TEST IF NOT
  820.     XCHG    BX,AX            ;MULTIPLY ORGINAL VALUE BY 10
  821.     MOV    CL,0AH            ;VALUE TO MULTIPLY BY
  822.     MUL    CL            ;DO IT
  823.     ADD    AL,BL            ;ADD IN NEW DIGIT
  824.     XCHG    BX,AX            ;PLACE IN CX REGISTER
  825. INIT3:    CMP    BX,63            ;IS IT GREATER THEN 64 K
  826.     JBE    INIT4            ;CONTINUE IF SO
  827.     MOV    BX,63            ;FOURCE TO TO 64K MAX
  828. INIT4:    MOV    AX,1024            ;VALUE FOR ONE K
  829.     MUL    BX            ;COMPUTE TOTAL NUMBER OF K
  830.     CMP    DX,+01            ;CHECK FOR 16 BIT OVER FLOW
  831.     JB    INIT5
  832.     MOV    AX,0FFFFH        ;MAKE A MASK FOR 64 K
  833. INIT5:    MOV    CS:BUF_SIZE,AX        ;SAVE SIZE OF BUFFER
  834. ;
  835. ;    NOW CHECK FOR PRINTER PORT TO USE
  836. ;
  837. INIT5A:    LODSB                ;GET NEXT CHARACTER IN THE STRING
  838.     CMP    AL,0DH            ;IS IT THE END OF LINE
  839.     JZ    INIT7            ;EXIT DETERMINATION IF SO
  840.     CMP    AL,2FH            ;IS IT A SLASH CHARACTER THAT SEPERATES VALUES
  841.     JZ    INIT6            ;CONTINUE IF SO
  842.     CMP    AL,2DH            ;IS IT A DASH THAT CAN SEPERATE IT TO
  843.     JNZ    INIT5A            ;IGNORE IF NOT
  844. INIT6:    LODSB                ;GET NEXT CHARACTER
  845.     AND    AL,0DFH            ;MAKE IT A UPPER CASE CHARACTER
  846.     CMP    AL,'C'            ;IS IT THE LETTER "c" FOR com PORT
  847.     JNZ    INIT10            ;IF NOT "c" THEN TEST FOR "l"
  848.     MOV    CS:[PORT_TYPE],0    ;SET PORT_TYPE TO com (VALUE OF 0)
  849.     JMP    INIT11            ;NOW GO GET PORT NUMBER 
  850. INIT10:    CMP    AL,'L'            ;IS IT THE LETTER "l" FOR lpt PORT
  851.     JNZ    INIT7            ;EXIT IF NOT A "L" OR "C"
  852.     MOV    CS:[PORT_TYPE],1    ;SET PORT_TYPE TO lpt (VALUE OF 1)
  853. INIT11:
  854.     LODSB                ;GET NEXT CHARACTER, WHICH SHOULD BE THE PORT NUMBER
  855.     SUB    AL,31H            ;CONVERT TO BINARY NUMBER
  856.     JB    INIT7            ;EXIT IF LESS THEN THE DIGIT "1"
  857.     CMP    AL,03            ;MAKE SURE NOT GREATER THEN "4"
  858.     JNB    INIT7            ;BYPASS IF ERROR
  859.  
  860.     CALL GET_PORT_ADDRESS    ; make sure the port is ready there
  861.     CMP DX, 0
  862.     JZ INIT7
  863.  
  864.     ;    CBW                ;MAKE 16 BIT VALUE
  865.     ;    PUSH    AX            ;SAVE THE PORT NUMBER ONTO THE STACK
  866.     ;    ADD    AX,AX            ;DOUBLE IT FOR TABLE LOOKUP
  867.     ;    MOV    BX,AX            ;PUT THE TABLE OFFSET VALUE INTO BX
  868.     ;    PUSH    ES            ;SAVE OUR SEGMENT REGISTER
  869.     ;    MOV    AX,0040H        ;SET OUR SEGMENT VALUE TO ROM BIOS AREA
  870.     ;    MOV    ES,AX            ;DO IT
  871.     ;    MOV    DI,0008*PORT_TYPE    ;DISPLACEMENT INTO THE BIOS AREA
  872.     ;    CMP    ES:WORD PTR[BX+DI],0    ;MAKE SURE THE PORT REALLY IS THERE
  873.     ;    POP    ES            ;RESTORE OUR PREVIOS DATA SEGMENT
  874.     ;    POP    AX            ;RESTORE PORT NUMBER FROM THE STACK
  875.     ;    JZ    INIT7            ;USE STANDARD PORT VALUE IF NOT
  876.     
  877.     MOV    CS:PORT_NUMBER,AL     ;SAVE THE PORT NUMBER FOR FUTURE USE
  878.     JMP    INIT8
  879. INIT7:    MOV    CS:[PORT_TYPE],1    ; lpt
  880.     MOV    CS:PORT_NUMBER,0     ;FOURCE PORT NUMBER TO LPT1:
  881. INIT8:    MOV    AX,CS            ;GET VALUE OF CURRENT CODE SEGMENT
  882.     MOV    DS,AX            ;SET DS TO POINT AT CODE SEGMENT
  883. ;
  884. ;    GET CURRENT INTERRUPT VECTOR FOR TIMER INTERRUPT
  885. ;
  886.     PUSH    ES            ;SAVE THE SEGMENT REGISTER 
  887.     MOV    AX,3508H        ;VECTOR NUMBER FOR IRQ0
  888.     INT    21H            ;GET THE VECTOR
  889.     MOV    WORD PTR PRTOUT9+1,BX    ;SAVE THE OFFSET
  890.     MOV    WORD PTR PRTOUT9+3,ES    ;SAVE THE SEGMENT IT WILL BELONG IN
  891.     POP      ES            ;RESTORE THE EXTRA SEGMENT REGISTER
  892. ;
  893. ;    SETUP INTERRUPT VECTOR 08H (timer) TO PRINT OUTPUT ROUTINE
  894. ;
  895. ;    MOV    AX,2508H        ;DOS REQUEST
  896. ;    MOV    DX,OFFSET PRTOUT    ;POINTER TO OUR ROUTINE
  897. ;    INT    21H
  898. ;
  899. ;    SETUP INTERRUPT VECTOR 65H TO POINT TO OUR buffer ROUTINE
  900. ;
  901.     MOV    AX,2565H        ;DOS REQUEST
  902.     MOV    DX,OFFSET STATUS    ;POINTER TO OUR ROUTINE
  903.     INT    21H
  904. ;
  905. ;    GET POINTER TO CURRENT PARALLEL PRINTER ROUTINE
  906. ;
  907.     PUSH    DS            ;SAVE OUR DATA SEGMENT ONTO THE STACK
  908.     MOV    AX,3517H        ;DOS REQUEST
  909.     INT    21H
  910. ;
  911. ;    TRANSFER IT TO INT 67h VECTOR FOR USE BY PROGRAMS THAT WANT TO
  912. ;    USE ADDITIONAL PRINTERS
  913. ;
  914.     PUSH    ES            ;SAVE THE SEGMENT ADDRESS ONTO STACK
  915.     POP    DS            ;RETURN IT IN DATA SEGMENT REGISTER
  916.     MOV    DX,BX            ;MOVE OFFSET TO DX REGISTER
  917.     MOV    AX,2567h        ;DOS REQUEST TO INIT 67h VECTOR
  918.     INT    21H
  919.     POP    DS            ;RESTORE OUR LOCAL DATA SEGMENT
  920. ;
  921. ;    SETUP CODE TO POINT PARALLEL PRINTER INTERCEPT ROUTINE
  922. ;
  923.     MOV    AX,2517H        ;DOS REQUEST
  924.     MOV    DX,OFFSET PAR_INCEP    ;POINTER TO OUR ROUTINE
  925.     INT    21H
  926.     
  927.     PUSH DS
  928.     MOV AH, 35H        ; get rs232_io vector and reassign it to vector 66H
  929.     MOV AL, 14H
  930.     INT 21H            ; es:bx = vector
  931.     PUSH ES
  932.     POP DS
  933.     MOV DX, BX
  934.     MOV AH, 25H
  935.     MOV AL, 66H
  936.     INT 21H
  937.     POP DS
  938.  
  939.     MOV AH, 25H        ; assign our com_incep routine to the old rs232_io int 14h
  940.     MOV AL, 14H
  941.     MOV DX, OFFSET COM_INCEP
  942.     INT 21H
  943. ;
  944. ;    COMPUTE STARTING SEGMENT FOR THE DATA BUFFER
  945. ;
  946.     MOV    BX,OFFSET INIT        ;POINT TO THE START OF OUR INIT ROUTINE    
  947.     MOV    AL,0FH            ;VALUE TO COMPUTE SEGMENT ADDRESS
  948.     AND    AL,BL            ;MASK OFF BOTTOM FOUR BITS
  949.     JZ    INIT9            ;ALLREADY ON SEGMENT BOUNDRY
  950.     ADD    BL,10H            ;BUMP LENGHT ON ONE SEGMENT
  951. INIT9:    MOV    DX,BX            ;PUT VALUE INTO DX
  952.     MOV    CL,04            ;AMOUNT TO SHIFT RIGHT
  953.     SHR    DX,CL            ;DO IT
  954.     MOV    AX,CS            ;GET CURRENT CODE SEGMENT
  955.     ADD    AX,DX            ;ADD TO OUR SEGMENT LENGTH
  956.     MOV    DATA_SEG,AX        ;SAVE THAT AS THE START OF OUR PRINTER BUFFER
  957.     MOV    AX,BUF_SIZE        ;GET THE CURRENT BUFFER SIZE
  958.     ADD    AX,BX            ;ADD IT TO THE CODE LENGHT
  959.     MOV [ENDING_ADDRESS], AX
  960.     LDS    SI,RH_SEG        ;FILL IN THE REQUEST HEADER THE POINT
  961.     MOV    [SI+0EH],AX        ;PAST OUR USEAGE
  962.     MOV    [SI+10H],CS
  963.     JMP    EXIT            ;SET STATUS WORD TO DONE AND EXIT
  964. INIT    ENDP
  965. CSEG    ENDS
  966.     END
  967.